// Object.defineProperty()方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象
// Object.defineProperty()方法可以给对象设置隐藏属性

var obj = {}
Object.defineProperty(obj, 'a', {
    value: 3,
    writable: false, // 设置是否可写
    enumerable: true
})
Object.defineProperty(obj, 'b', {
    value: 5,
    enumerable: false // 设置是否可以被枚举
})


// JS引擎的数据劫持方法
Object.defineProperty(obj, 'c', {
    // getter函数：访问属性值时被调用
    get () {
        console.log('你正在试图读取c的值')
        return 7
    },
    // setter函数：修改属性值时被调用
    set(newValue) {
        console.log('你正在试图修改c的值为：', newValue)
    }
})
obj.c++
console.log('c:',obj.c) // 最终c的值还是未被修改

// getter和setter需要添加临时变量才能被真正修改
let tempValue
Object.defineProperty(obj, 'd', {
    // getter函数：访问属性值时被调用
    get () {
        return tempValue
    },
    // setter函数：修改属性值时被调用
    set(newValue) {
        tempValue = newValue
    }
})
obj.d = 10
console.log('d:',obj.d) 
obj.d++
console.log('d:',obj.d) 

// 因此进行封装，通过defineReactive函数完成了一个基础的数据的响应式（不支持属性嵌套）
var obj = {}
function defineReactive (data, key, val) {
    if (arguments.length == 2) {
        val = data[key]
    }
    // 通过val构建了一个闭包环境
    Object.defineProperty(data, key, {
        enumerable: true, // 可枚举
        configurable: true, // 可以被配置，例如delete
        // getter函数：访问属性值时被调用
        get () {
            console.log('你正在试图读取属性值:',val)
            return val
        },
        // setter函数：修改属性值时被调用
        set(newValue) {
            if (val == newValue) {
                return
            }
            console.log('你正在试图修改属性值:',val)
            val = newValue
        }
    })
}
defineReactive(obj, 'e', 12)
console.log('e:',obj.e) 
obj.e++
console.log('e:',obj.e) 